

export class DBScan
{

    // 对数据进行分类
    /**
     * @data 样本数据
     * @r 半径
     * @samplecount 样本数目阈值
    */
     public static classify<T extends ISample>(data:T[],samplecount:number, r:number,recursion_time=1)
     {
         let leftData = _.clone(data);
         let d_r = r;
         const clusters:Set<T>[]=[];
        while(recursion_time>0 && leftData.length>0)
        {
            const result = this._classify(leftData,samplecount,d_r);
            d_r =d_r*2;
            recursion_time--;
            leftData = result.left;
            clusters.push(...result.cluster);
        }
        return {cluster:clusters,left:leftData};
     }
    // 对数据进行分类
    /**
     * @data 样本数据
     * @r 半径
     * @samplecount 样本数目阈值
    */
    public static  _classify<T extends ISample>(data:T[],samplecount:number,r:number)
    {
        // 1.
        const coresample:T[]=[];
        for(let i=0;i<data.length;i++)
        {
            let count=0;
            for(let j=0;j<data.length;j++)
            {
                if(i==j)
                {
                    continue;
                }

                if(data[i].isInRange(data[j],r))
                {
                    count++;
                    data[i].addNab(data[j]);
                }
            }

            if(count>=samplecount)
            {
                coresample.push(data[i]);
            }
        }

        // 2.
        let allVisitsamples:Set<T> = new Set<T>();
        const clusters = [];
        for(const coresam of coresample)
        {
            if(allVisitsamples.has(coresam))
            {
                continue;
            }
            const cluster:Set<T> = new Set<T>();
            let nextVisit = [coresam];
            while(nextVisit.length>0)
            {
                let nexttemp:T[]=[];
                for(const item of nextVisit)
                {
                    cluster.add(item);
                    allVisitsamples.add(item);
                    for(const nab of item.getNabs())
                    {
                        if( cluster.has(nab as T))
                        {
                            continue;
                        }
                        nexttemp.push(nab as T)
                    }
                }

                nextVisit = nexttemp;
            }
            clusters.push(cluster);
        }
        const left=_.filter(data,item=>!allVisitsamples.has(item))
        return {cluster:clusters,left:left};
    }
}
